package win.doyto.service.data.report.support;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.View;
import win.doyto.service.data.config.ReportConfigEntity;
import win.doyto.service.data.config.ReportParam;
import win.doyto.service.data.report.AbstractReportView;
import win.doyto.service.data.report.ReportMapper;
import win.doyto.service.data.report.ReportService;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.*;
import javax.annotation.Resource;

import static org.apache.commons.lang3.ArrayUtils.EMPTY_STRING_ARRAY;

/**
 * ReportCsvService
 *
 * @author f0rb on 2017-12-20.
 */
@Slf4j
@Service
public class ReportCsvService implements ReportService {

    @Resource
    private ReportMapper reportMapper;

    @Override
    @Transactional
    public String fetchAndWrite(OutputStream output, List<ReportConfigEntity> reportConfigEntities, Map<String, Object> params) {

        ReportConfigEntity reportConfigEntity = reportConfigEntities.get(0);
        //创建sheet
        params.put(reportMapper.SQL_KEY, reportConfigEntity.getReportSql());
        Iterator<LinkedHashMap<String, Object>> data;
        data = reportMapper.getData(params).iterator();

        ReportParam reportParam = reportConfigEntity.reportParam();

        // csv文件的编码
        Charset csvCharset = Charset.forName(reportParam.getCsvCharset());
        byte[] csvRowSeparator = "\n".getBytes(csvCharset);
        byte[] csvColSeparator = reportParam.getCsvColSeparator().getBytes(csvCharset);

        int row = 0;
        if (data.hasNext()) {

            LinkedHashMap<String, Object> first = data.next();
            String[] titles = first.keySet().toArray(EMPTY_STRING_ARRAY);
            for (String title : titles) {
                try {
                    output.write(String.valueOf(title).getBytes(csvCharset));
                    output.write(csvColSeparator);
                } catch (IOException e) {
                    log.warn("数据写入错误: title=" + title, e);
                }
            }
            try {
                output.write(csvRowSeparator);
            } catch (IOException e) {
                log.warn("数据写入错误", e);
            }


            row = writeData(output, data, csvCharset, csvRowSeparator, csvColSeparator, row);
        }

        log.debug("总计处理{}行数据!", row);

        //文件名格式化
        String filename = reportConfigEntity.getReportName().replace("%D", DateFormatUtils.format(new Date(), "yyyyMMdd"));
        if (!filename.endsWith(".csv")) {
            filename = filename + ".csv";
        }
        return filename;

    }

    private int writeData(OutputStream output, Iterator<LinkedHashMap<String, Object>> data, Charset csvCharset, byte[] csvRowSeparator, byte[] csvColSeparator, int row) {
        while (data.hasNext()) {
            row++;
            if (row % 500 == 0) {
                log.debug("已处理{}行数据", row);
            }

            LinkedHashMap<String, Object> result = data.next();
            Object[] dataRow = result.values().toArray();
            for (int col = 0; col < dataRow.length; col++) {
                try {
                    output.write(String.valueOf(dataRow[col]).getBytes(csvCharset));
                    output.write(csvColSeparator);
                } catch (IOException e) {
                    log.warn("数据写入错误: " + row + ":" + col, e);
                }
            }
            try {
                output.write(csvRowSeparator);
            } catch (IOException e) {
                log.warn("数据写入错误: " + row, e);
            }
        }
        return row;
    }

    @Override
    public String getExtension() {
        return "csv";
    }

    @Bean
    View csvView(ReportService reportCsvService) {
        return new AbstractReportView(reportCsvService, "text/csv");
    }

}
